"""
FastAPI 客户端示例
演示如何使用 Python 调用 FastAPI 后端 API
"""
import requests
import json
from typing import Optional, Dict, List


class FastAPIClient:
    """FastAPI 客户端类，封装所有 API 调用"""
    
    def __init__(self, base_url: str = "http://localhost:8000/api"):
        """
        初始化客户端
        
        Args:
            base_url: API 基础地址
        """
        self.base_url = base_url
        self.token: Optional[str] = None
        self.session = requests.Session()
    
    def _get_headers(self, include_auth: bool = True) -> Dict[str, str]:
        """
        获取请求头
        
        Args:
            include_auth: 是否包含认证令牌
            
        Returns:
            dict: 请求头字典
        """
        headers = {"Content-Type": "application/json"}
        if include_auth and self.token:
            headers["Authorization"] = f"Bearer {self.token}"
        return headers
    
    def register(self, username: str, email: str, password: str) -> Dict:
        """
        用户注册
        
        Args:
            username: 用户名
            email: 邮箱
            password: 密码
            
        Returns:
            dict: 注册结果，包含用户信息或错误信息
            
        Raises:
            requests.RequestException: 请求失败时抛出
        """
        url = f"{self.base_url}/auth/register"
        data = {
            "username": username,
            "email": email,
            "password": password
        }
        
        try:
            response = self.session.post(
                url,
                json=data,
                headers=self._get_headers(include_auth=False)
            )
            response.raise_for_status()
            return {"success": True, "data": response.json()}
        except requests.exceptions.HTTPError as e:
            error_detail = e.response.json().get("detail", "注册失败")
            return {"success": False, "error": error_detail}
        except requests.exceptions.RequestException as e:
            return {"success": False, "error": str(e)}
    
    def login(self, username: str, password: str) -> Dict:
        """
        用户登录
        
        Args:
            username: 用户名
            password: 密码
            
        Returns:
            dict: 登录结果，包含 token 或错误信息
        """
        url = f"{self.base_url}/auth/login"
        data = {
            "username": username,
            "password": password
        }
        
        try:
            # 登录接口使用表单数据格式
            response = self.session.post(
                url,
                data=data,
                headers={"Content-Type": "application/x-www-form-urlencoded"}
            )
            response.raise_for_status()
            result = response.json()
            self.token = result.get("access_token")
            return {"success": True, "data": result}
        except requests.exceptions.HTTPError as e:
            error_detail = e.response.json().get("detail", "登录失败")
            return {"success": False, "error": error_detail}
        except requests.exceptions.RequestException as e:
            return {"success": False, "error": str(e)}
    
    def get_current_user(self) -> Dict:
        """
        获取当前登录用户信息
        
        Returns:
            dict: 用户信息或错误信息
        """
        url = f"{self.base_url}/auth/me"
        
        try:
            response = self.session.get(
                url,
                headers=self._get_headers()
            )
            response.raise_for_status()
            return {"success": True, "data": response.json()}
        except requests.exceptions.HTTPError as e:
            if e.response.status_code == 401:
                self.token = None  # 清除无效 token
            error_detail = e.response.json().get("detail", "获取用户信息失败")
            return {"success": False, "error": error_detail}
        except requests.exceptions.RequestException as e:
            return {"success": False, "error": str(e)}
    
    def get_users(self, skip: int = 0, limit: int = 100) -> Dict:
        """
        获取用户列表
        
        Args:
            skip: 跳过记录数
            limit: 返回记录数
            
        Returns:
            dict: 用户列表或错误信息
        """
        url = f"{self.base_url}/users/"
        params = {"skip": skip, "limit": limit}
        
        try:
            response = self.session.get(
                url,
                params=params,
                headers=self._get_headers(include_auth=False)
            )
            response.raise_for_status()
            return {"success": True, "data": response.json()}
        except requests.exceptions.RequestException as e:
            return {"success": False, "error": str(e)}
    
    def get_user(self, user_id: int) -> Dict:
        """
        根据ID获取单个用户信息
        
        Args:
            user_id: 用户ID
            
        Returns:
            dict: 用户信息或错误信息
        """
        url = f"{self.base_url}/users/{user_id}"
        
        try:
            response = self.session.get(
                url,
                headers=self._get_headers(include_auth=False)
            )
            response.raise_for_status()
            return {"success": True, "data": response.json()}
        except requests.exceptions.HTTPError as e:
            error_detail = e.response.json().get("detail", "获取用户信息失败")
            return {"success": False, "error": error_detail}
        except requests.exceptions.RequestException as e:
            return {"success": False, "error": str(e)}
    
    def update_user(self, username: Optional[str] = None, 
                   email: Optional[str] = None,
                   password: Optional[str] = None) -> Dict:
        """
        更新当前用户信息
        
        Args:
            username: 新用户名（可选）
            email: 新邮箱（可选）
            password: 新密码（可选）
            
        Returns:
            dict: 更新后的用户信息或错误信息
        """
        url = f"{self.base_url}/users/me"
        data = {}
        
        if username:
            data["username"] = username
        if email:
            data["email"] = email
        if password:
            data["password"] = password
        
        if not data:
            return {"success": False, "error": "至少需要提供一个更新字段"}
        
        try:
            response = self.session.put(
                url,
                json=data,
                headers=self._get_headers()
            )
            response.raise_for_status()
            return {"success": True, "data": response.json()}
        except requests.exceptions.HTTPError as e:
            if e.response.status_code == 401:
                self.token = None  # 清除无效 token
            error_detail = e.response.json().get("detail", "更新用户信息失败")
            return {"success": False, "error": error_detail}
        except requests.exceptions.RequestException as e:
            return {"success": False, "error": str(e)}
    
    def logout(self):
        """清除本地 token（注意：后端不维护会话，这是本地操作）"""
        self.token = None


def example_1_register():
    """示例1：用户注册"""
    print("=" * 50)
    print("示例1：用户注册")
    print("=" * 50)
    
    client = FastAPIClient()
    
    # 注册新用户
    result = client.register(
        username="pythonuser",
        email="pythonuser@example.com",
        password="python123"
    )
    
    if result["success"]:
        print("✅ 注册成功！")
        print(f"用户信息：{json.dumps(result['data'], indent=2, ensure_ascii=False)}")
    else:
        print(f"❌ 注册失败：{result['error']}")
    
    print()


def example_2_login():
    """示例2：用户登录"""
    print("=" * 50)
    print("示例2：用户登录")
    print("=" * 50)
    
    client = FastAPIClient()
    
    # 登录
    result = client.login(
        username="pythonuser",
        password="python123"
    )
    
    if result["success"]:
        print("✅ 登录成功！")
        print(f"Token: {result['data']['access_token'][:50]}...")
        print(f"Token 类型: {result['data']['token_type']}")
        return client  # 返回已登录的客户端
    else:
        print(f"❌ 登录失败：{result['error']}")
        return None
    
    print()


def example_3_get_current_user(client: FastAPIClient):
    """示例3：获取当前用户信息"""
    print("=" * 50)
    print("示例3：获取当前用户信息")
    print("=" * 50)
    
    if not client or not client.token:
        print("❌ 请先登录")
        return
    
    result = client.get_current_user()
    
    if result["success"]:
        print("✅ 获取用户信息成功！")
        print(f"用户信息：{json.dumps(result['data'], indent=2, ensure_ascii=False)}")
    else:
        print(f"❌ 获取失败：{result['error']}")
    
    print()


def example_4_get_users():
    """示例4：获取用户列表"""
    print("=" * 50)
    print("示例4：获取用户列表")
    print("=" * 50)
    
    client = FastAPIClient()
    
    # 获取前10个用户
    result = client.get_users(skip=0, limit=10)
    
    if result["success"]:
        users = result["data"]
        print(f"✅ 获取成功，共 {len(users)} 个用户：")
        for user in users:
            print(f"  - ID: {user['id']}, 用户名: {user['username']}, 邮箱: {user['email']}")
    else:
        print(f"❌ 获取失败：{result['error']}")
    
    print()


def example_5_get_user_by_id():
    """示例5：根据ID获取用户"""
    print("=" * 50)
    print("示例5：根据ID获取用户")
    print("=" * 50)
    
    client = FastAPIClient()
    
    # 获取ID为1的用户
    result = client.get_user(1)
    
    if result["success"]:
        print("✅ 获取成功！")
        print(f"用户信息：{json.dumps(result['data'], indent=2, ensure_ascii=False)}")
    else:
        print(f"❌ 获取失败：{result['error']}")
    
    print()


def example_6_update_user(client: FastAPIClient):
    """示例6：更新用户信息"""
    print("=" * 50)
    print("示例6：更新用户信息")
    print("=" * 50)
    
    if not client or not client.token:
        print("❌ 请先登录")
        return
    
    # 更新用户信息（只更新邮箱）
    result = client.update_user(email="newemail@example.com")
    
    if result["success"]:
        print("✅ 更新成功！")
        print(f"更新后的用户信息：{json.dumps(result['data'], indent=2, ensure_ascii=False)}")
    else:
        print(f"❌ 更新失败：{result['error']}")
    
    print()


def example_7_complete_workflow():
    """示例7：完整工作流程"""
    print("=" * 50)
    print("示例7：完整工作流程（注册 -> 登录 -> 获取信息 -> 更新）")
    print("=" * 50)
    
    import random
    import string
    
    # 生成随机用户名，避免重复
    random_str = ''.join(random.choices(string.ascii_lowercase + string.digits, k=6))
    username = f"testuser_{random_str}"
    email = f"{username}@example.com"
    password = "test123456"
    
    client = FastAPIClient()
    
    # 步骤1：注册
    print("📝 步骤1：注册新用户...")
    register_result = client.register(username, email, password)
    if not register_result["success"]:
        print(f"⚠️ 注册失败（可能用户已存在）：{register_result['error']}")
        print("   尝试使用现有用户登录...")
        login_result = client.login(username, password)
        if not login_result["success"]:
            print(f"❌ 登录也失败：{login_result['error']}")
            return
    else:
        print(f"✅ 注册成功：{username}")
    
    # 步骤2：登录
    print("\n🔐 步骤2：登录...")
    login_result = client.login(username, password)
    if login_result["success"]:
        print(f"✅ 登录成功，Token: {login_result['data']['access_token'][:30]}...")
    else:
        print(f"❌ 登录失败：{login_result['error']}")
        return
    
    # 步骤3：获取当前用户信息
    print("\n👤 步骤3：获取当前用户信息...")
    user_result = client.get_current_user()
    if user_result["success"]:
        user = user_result["data"]
        print(f"✅ 当前用户：{user['username']} ({user['email']})")
    else:
        print(f"❌ 获取失败：{user_result['error']}")
        return
    
    # 步骤4：更新用户信息
    print("\n✏️ 步骤4：更新用户邮箱...")
    new_email = f"updated_{username}@example.com"
    update_result = client.update_user(email=new_email)
    if update_result["success"]:
        print(f"✅ 更新成功，新邮箱：{update_result['data']['email']}")
    else:
        print(f"❌ 更新失败：{update_result['error']}")
    
    print("\n✅ 完整流程执行完毕！")


def main():
    """主函数：运行所有示例"""
    print("\n" + "=" * 50)
    print("FastAPI Python 客户端示例")
    print("=" * 50 + "\n")
    
    # 运行各个示例
    example_1_register()
    example_2_login()
    
    # 登录后继续其他示例
    client = example_2_login()
    if client:
        example_3_get_current_user(client)
        example_6_update_user(client)
    
    example_4_get_users()
    example_5_get_user_by_id()
    
    # 完整工作流程
    print("\n")
    example_7_complete_workflow()
    
    print("\n" + "=" * 50)
    print("所有示例执行完毕！")
    print("=" * 50 + "\n")


if __name__ == "__main__":
    main()

